package ch.ti.bfh.app.loodel.domain.timeslot;

import ch.ti.bfh.app.loodel.domain.learningEvent.LearningEvent;
import ch.ti.bfh.app.loodel.domain.timeslotvote.TimeSlotVote;
import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.PeriodFormatterBuilder;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.Locale;

@Entity
public class TimeSlot {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    private LearningEvent learningEvent;

    @Embedded
    private Location location;

    private String comment;

    private boolean takingPlace = false;

    @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    private DateTime creationTime;

    @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
    private DateTime lastUpdatedTime;

    private int voteCount;

    @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDateTime")
    @NotNull
    private LocalDateTime startDateTime;

    @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDateTime")
    @NotNull
    private LocalDateTime endDateTime;

    public TimeSlot(LearningEvent learningEvent, Interval dateTimeInterval, Location location) {
        this.learningEvent = learningEvent;
        this.location = location;
        this.takingPlace = false;
        this.voteCount = 0;
        this.startDateTime = dateTimeInterval.getStart().toLocalDateTime();
        this.endDateTime = dateTimeInterval.getEnd().toLocalDateTime();
    }

    /**
     * FOR JPA
     */
    protected TimeSlot() {
    }

    @PreUpdate
    @PrePersist
    public void updateTimeStamps() {
        lastUpdatedTime = new DateTime();
        if (creationTime == null) {
            creationTime = new DateTime();
        }
    }

    public String getDuration() {
        PeriodFormatterBuilder daysHoursMinutes = new PeriodFormatterBuilder().appendDays().appendSuffix("d ").appendHours().appendSuffix("h ").appendMinutes().appendSuffix("min");
        String print = daysHoursMinutes.toFormatter().print(this.getInterval().toPeriod().normalizedStandard());
        return StringUtils.trim(print);
    }

    public String getShortStartDateTime() {
        return DateTimeFormat.shortDateTime().print(this.getInterval().getStart());
    }

    public String getShortStartDateTime(Locale locale) {
        return DateTimeFormat.shortDateTime().withLocale(locale).print(this.getInterval().getStart());
    }

    public String getShortEndDateTime() {
        return DateTimeFormat.shortDateTime().print(this.getInterval().getEnd());
    }

    public Long getId() {
        return id;
    }


    public Location getLocation() {
        return location;
    }

    public void setLocation(Location location) {
        this.location = location;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public boolean getTakingPlace() {
        return takingPlace;
    }

    public void setTakingPlace(boolean takingPlace) {
        this.takingPlace = takingPlace;
    }

    public LearningEvent getLearningEvent() {
        return learningEvent;
    }


    public Interval getInterval() {
        return new Interval(this.startDateTime.toDateTime(), this.endDateTime.toDateTime());
    }

    public String getTimeSlotLongTitle() {
        return learningEvent.getModulName() + "@ " + this.getTimeSlotShortTitle();
    }

    public String getTimeSlotShortTitle() {
        return this.location.getName() + " Duration: " + this.getDuration() + " Votes: " + this.getVoteCount();
    }

    public int getVoteCount() {
        return voteCount;
    }

    private void increaseVoteCount() {
        this.voteCount++;
    }

    private void decrementVoteCount() {
        if (this.voteCount == 0) {
            throw new IllegalStateException("Can not decrement vote cause no vote has been given");
        }
        this.voteCount--;
    }


    public void addTimeSlotVote(TimeSlotVote timeSlotVote) {
        if (this.getLearningEvent().getVotesClosed()) {
            throw new IllegalStateException("Learning Event Vote already Closed");
        }
        this.increaseVoteCount();
    }

    public void removeTimeSlotVote(TimeSlotVote timeSlotVote) {
        if (this.getLearningEvent().getVotesClosed()) {
            throw new IllegalStateException("Learning Event Vote already Closed");
        }
        this.decrementVoteCount();
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof TimeSlot)) return false;

        TimeSlot timeSlot = (TimeSlot) o;

        if (id != null ? !id.equals(timeSlot.id) : timeSlot.id != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }
}
